package ink.tiptop.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import ink.tiptop.persist.domain.entity.ZjfModuleLocalEntity;
import ink.tiptop.dto.req.local.module.*;
import ink.tiptop.enums.EResp;
import ink.tiptop.common.domain.WebworkResponse;
import ink.tiptop.dto.resp.local.ZjfModuleLocalInfo;
import ink.tiptop.common.GenericBuilder;
import ink.tiptop.common.cache.CacheAble;
import ink.tiptop.common.cache.CacheEvict;
import ink.tiptop.common.cache.ECaches;
import ink.tiptop.common.cache.ICache;
import ink.tiptop.constant.Proof;
import ink.tiptop.constant.Rgx;
import ink.tiptop.enums.EOutputType;
import ink.tiptop.exception.JDTException;
import ink.tiptop.exception.JDTExceptionMsg;
import ink.tiptop.common.worker.scan.LocalScanner;
import ink.tiptop.persist.dao.ZjfModuleLocalMapper;
import ink.tiptop.common.domain.req.PageRequest;
import ink.tiptop.common.domain.rsp.Response;
import ink.tiptop.common.domain.rsp.SucceedResponse;
import ink.tiptop.service.*;
import ink.tiptop.utils.JSON;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.File;
import java.util.*;
import java.util.stream.Collectors;
/**
 * 本地模块结构视图(ZjfModuleLocalEntity)表服务实现类
 *
 * @author makejava
 * @since 2020-06-21 20:39:55
 */
@Service("zjfModuleLocalService")
@Slf4j
public class ZjfModuleLocalServiceImpl extends AbstractBaseService<ZjfModuleLocalEntity> implements ZjfModuleLocalService {
    private static final String CACHE_KEY = "MODULE_LOCAL";
    private static final String CACHE_CLEAR = CACHE_KEY + "*";

    // 维护一个排序字段映射,前端传递 PARENT -> 排序映射 parent
    private static final Map<String, String> orderByMap = new HashMap<>();

    static {
//        orderByMap.put("PARENT", "parent");
        orderByMap.put("NAME", "name");
        orderByMap.put("IGNORE", "ignore");
        orderByMap.put("REMOTE_NAME", "remote_id");
        orderByMap.put("PARENT", "parent");
    }

    @Resource
    private ZjfModuleLocalMapper zjfModuleLocalMapper;
    @Autowired
    private ZjfAuthUserInfoService authUserInfoService;
    @Autowired
    private ZjfUserModuleVersionService userModuleVersionService;

    /**
     * 通过ID查询单条数据
     *
     * @param id 主键
     * @return 实例对象
     */
    @Override
    public ZjfModuleLocalEntity queryById(Integer id) {
        return this.zjfModuleLocalMapper.selectById(id);
    }

    @Autowired
    private CacheSearch<ZjfModuleLocalEntity> cacheSearch;

    /**
     * 新增数据
     *
     * @return 实例对象
     */
    @Override
    public ZjfModuleLocalEntity insert(ZjfModuleLocalEntity zjfModuleLocalEntity) {
        this.zjfModuleLocalMapper.insert(zjfModuleLocalEntity);
        return zjfModuleLocalEntity;
    }

    /**
     * 通过主键删除数据
     *
     * @param id 主键
     * @return 是否成功
     */
    @Override
    public boolean deleteById(String id) {
        return this.zjfModuleLocalMapper.deleteById(id) > 0;
    }

    @Override
    @CacheAble(desc = "本地模块查询缓存", keyPrefix = CACHE_KEY,type = ECaches.DAY)
    public Response list(QueryZjfModuleLocalRequest request) {
        return super.list(request);
    }

    @Override
    protected void setOrderBy(PageRequest request) {
        /*if (StringUtils.isNoneBlank(request.getSortType())
                && StringUtils.isNoneBlank(request.getSortName())) {
            // 这里直接设置了排序,比如 create_time  desc
            String orderColumnMap = orderByMap.get(request.getSortName());
            if (orderColumnMap!=null) {
                String orderByString = String.format(ORDER_BY_FORMAT, orderColumnMap, request.getSortType());
                PageHelper.orderBy(orderByString);
            }
        }*/
    }

    /**
     * 组装请求参数
     *
     * @param request
     * @return
     */
    @Override
    protected ZjfModuleLocalEntity getQueryParam(PageRequest request) {
        ZjfModuleLocalEntity entity = new ZjfModuleLocalEntity();
        BeanUtils.copyProperties(request, entity);
        if (StringUtils.isNotBlank(request.getSearch())) {
            entity.setName("%" + request.getSearch().trim() + "%");
        }
        return entity;
    }

    @Autowired
    private ICache<String> cache;

    /**
     * 组装响应参数,这里其实是list,为了扩展 ,写成了Object
     *
     * @param voList
     * @return
     */
    @Override
    protected Object getResponseList(List<ZjfModuleLocalEntity> voList) {
        List<ZjfModuleLocalInfo> infos = new ArrayList<>();
        ZjfModuleLocalInfo info;

        for (ZjfModuleLocalEntity entity : voList) {
            info = new ZjfModuleLocalInfo();
            BeanUtils.copyProperties(entity, info);
            infos.add(info);
        }
        return infos;
    }

    /**
     * 查询多条数据
     *
     * @return 对象列表
     */
    @Override
    public List<ZjfModuleLocalEntity> queryAllByUser(String user) {
        String cacheKey = CACHE_KEY +"ALL"+user;
        List<ZjfModuleLocalEntity> list = cacheSearch.getList(cacheKey, ZjfModuleLocalEntity.class, ECaches.DAY);
        if (list == null) {
            ZjfModuleLocalEntity entity = new ZjfModuleLocalEntity();
            entity.setUser(user);
            list = this.zjfModuleLocalMapper.selectList(new QueryWrapper<>(entity));
            cache.setVal(cacheKey, JSON.toJSONString(list),ECaches.DAY);
        }
        return list;
    }

    /**
     * 查询数据库,返回list
     * TODO 待测试
     * @param param
     * @return
     */
    @Override
    protected Page<ZjfModuleLocalEntity> getQueryEntityList(Page<ZjfModuleLocalEntity> page, ZjfModuleLocalEntity param) {
        QueryWrapper<ZjfModuleLocalEntity> wrapper = new QueryWrapper<>(param);
        if (StringUtils.isNotBlank(param.getName())) {
            wrapper.like(true,"`name`",param.getName());
        }
        return zjfModuleLocalMapper.selectPage(page,wrapper);
    }

    @Override
    @CacheEvict(key = CACHE_CLEAR,type = ECaches.DAY)
    public Response update(UpdateZjfModuleLocalRequest request) {
        ZjfModuleLocalEntity entity = new ZjfModuleLocalEntity();
        BeanUtils.copyProperties(request, entity);
        int rows = 0;
        try {
            rows = zjfModuleLocalMapper.updateById(entity);
        } catch (Exception e) {
            if (e instanceof DuplicateKeyException) {
                return WebworkResponse.failed(EResp.EServerInfo.ERROR_EXIST);
            }
        }
        if (rows > 0) {
            return WebworkResponse.SUCCEED;
        }
        return WebworkResponse.ERROR;
    }

    @Override
    @CacheEvict(key = CACHE_CLEAR,type = ECaches.DAY)
    public Response delete(DeleteZjfModuleLocalRequest request) {
        int rows = zjfModuleLocalMapper.deleteBatchIds(request.getId());
        if (rows > 0) {
            return WebworkResponse.SUCCEED;
        }
        return WebworkResponse.ERROR;
    }

    @Override
    @CacheEvict(key = CACHE_CLEAR,type = ECaches.DAY)
    public Response add(AddZjfModuleLocalRequest request) {
        ZjfModuleLocalEntity entity = new ZjfModuleLocalEntity();

        entity.setParent(request.getParent());
        entity.setName(request.getName());
        entity.setUser(request.getUser());
        entity.setVersion(request.getVersion());
        int count = zjfModuleLocalMapper.selectCount(new QueryWrapper<>(entity));
        if (count > 0) {
            return WebworkResponse.failed(EResp.EModuleLocal.ERROR_EXIST);
        }
        BeanUtils.copyProperties(request, entity);
        scanLocalModule(entity);
        int rows = zjfModuleLocalMapper.insert(entity);
        if (rows > 0) {
            return WebworkResponse.SUCCEED;
        }
        return WebworkResponse.ERROR;
    }


    @Override
    @CacheEvict(key = CACHE_CLEAR,type = ECaches.DAY)
    public Response scan(ScanZjfModuleLocalRequest request) {
        // 1.校验参数是否都存在
        // 1.1用户
        authUserInfoService.checkUserExist(request.getUser());
        // 1.2版本
        userModuleVersionService.checkVersionExist(request.getUser(), request.getVersion());
        // 2.扫描+匹配过程
        //  2.1 获取本地扫描到的项目下的target下的 *.jar的包名称listA
        String pathLocals = request.getPathLocal();
        String[] pathLocal = pathLocals.split(",");
        List<String> localPathList = new ArrayList<>();
        for (String path : pathLocal) {
            localPathList.add(path.trim());
        }
        LocalScanner scanner = GenericBuilder
                .of(() -> new LocalScanner(localPathList,true))
                .build();
        // /Users/zhongjiafeng/Desktop/Project/Company/kunshan-trunk/bts-common-sdk/
        // target/bts-common-sdk-0.0.4-KS-SNAPSHOT.jar
        List<String> localJarList = scanner.scan(Rgx.JAR_NAME);

        if (localJarList == null || localJarList.isEmpty()) {
            return WebworkResponse.failed(EResp.EViewLocal.ERROR_SCAN);
        }

        ZjfModuleLocalEntity entity;
        for (String jarPath : localJarList) {
            String unixPath = jarPath.replaceAll("\\\\", "/");
            // /Users/zhongjiafeng/Desktop/Project/Company
            // /kunshan-trunk/bts-common-sdk/targt/bts-common-sdk-0.0.4-KS-SNAPSHOT.jar
            String[] all = unixPath.split("/");
            String s1 = all[all.length - 1];
            // 这个parent用于入库,如不不报异常 下面就是 target 然后就是 *.jar
            String target = all[all.length - 2];
            if (!target.toLowerCase().equals("target")) {
                continue;
            }
            // 把最后的/去掉
            String parent = unixPath.substring(0, unixPath.indexOf(all[all.length - 3]) - 1);
            //  .../webwork/lib/webwork-0.0.1-SNAPSHOT.jar
            entity = getZjfModuleLocalEntity(request, all, target, parent);

            int rows = zjfModuleLocalMapper.insert(entity);
            if (rows > 0) {
                log.info("插入成功,{}", entity.getId());
            } else {
                log.info("插入失败,{}", entity.getId());
            }
        }
        return SucceedResponse.SUCCEED;
    }

    @Override
    public List<ZjfModuleLocalEntity> queryAllByEntity(ZjfModuleLocalEntity moduleLocalEntity) {
        return zjfModuleLocalMapper.selectList(new QueryWrapper<>(moduleLocalEntity));
    }

    @Override
    public List<ZjfModuleLocalEntity> listByIds(List<Integer> id) {
        return zjfModuleLocalMapper.selectBatchIds(id);
    }


    private ZjfModuleLocalEntity getZjfModuleLocalEntity(ScanZjfModuleLocalRequest request, String[] all, String target, String parent) {
        ZjfModuleLocalEntity entity = new ZjfModuleLocalEntity();
        entity.setParent(parent);
        entity.setName(all[all.length - 3]);
        entity.setType(0);
        entity.setOriSrc(Proof.ORI_SRC);
        entity.setOriPom(Proof.ORI_POM);
        entity.setOutputTarget("/" + target);
        entity.setOutputJar("/" + all[all.length - 1]);
        entity.setDesc("扫描添加");
        entity.setVersion(request.getVersion());
        entity.setUser(request.getUser());
        entity.setOutputType(0);
        entity.setIgnore(0);
        return entity;
    }

    /**
     * 扫描本地模块
     *
     * @param request
     */
    private void scanLocalModule(ZjfModuleLocalEntity request) {
        // 1.先校验模块是否存在
        File file = new File(request.getParent(), request.getName());
        if (!file.exists() || file.isFile()) {
            JDTException.throwException(JDTExceptionMsg.getError(EResp.EModuleLocal.ERROR_SCAN));
        }
        switch (EOutputType.valueOfMap(request.getOutputType())) {
            case STANDARD:
                Optional<File> target = Optional.ofNullable(new File(file, "target"));
                if (!target.isPresent() || !target.get().exists() || target.get().isFile()) {
                    JDTException.throwException(JDTExceptionMsg.getError(EResp.EModuleLocal.ERROR_INSTALL_FIRST));
                }
                LocalScanner localScanner = new LocalScanner(target.get().getAbsolutePath(), 1);
                List<String> scanList = localScanner.scan(Rgx.JAR_NAME);
                if (scanList == null || scanList.isEmpty()) {
                    JDTException.throwException(JDTExceptionMsg.getError(EResp.EModuleLocal.ERROR_INSTALL_SCAN_JAR));
                }
                if (scanList.size() > 1) {
                    JDTException.throwException(JDTExceptionMsg.getError(EResp.EModuleLocal.ERROR_INSTALL_SCAN_JAR_TO_MANY));
                }
                String jar = scanList.get(0);
                String[] split = jar.replace("\\\\", "/").split("/");

                request.setOriSrc(Proof.ORI_SRC);
                request.setOriPom(Proof.ORI_POM);
                // 这里不确定是否带版本号的输出,用*代替了
                request.setOutputJar("/"+split[split.length - 1]);
//                request.setOutputLib("/target/lib"); // 不一定有
//                request.setOutputResource("/target/resources");// 不一定有
                request.setOutputTarget(Proof.OUTPUT_TARGET);
                break;
            case CUSTOMER:
                blankForbid(request.getOriSrc(), EResp.EViewLocal.ERROR_PARAM_SRC);
                blankForbid(request.getOriPom(), EResp.EViewLocal.ERROR_PARAM_POM);
                blankForbid(request.getOutputJar(), EResp.EViewLocal.ERROR_PARAM_JAR);
                blankForbid(request.getOutputTarget(), EResp.EViewLocal.ERROR_PARAM_TARGET);
                break;
            default:
                JDTException.throwException(JDTExceptionMsg.getError(EResp.EViewLocal.ERROR_PARAM));
                break;
        }
    }

    private void blankForbid(String param, EResp.EViewLocal errorParamSrc) {
        if (StringUtils.isBlank(param)) {
            JDTException.throwException(JDTExceptionMsg.getError(errorParamSrc));
        }
    }

    @Override
    public void update(Observable o, Object arg) {
        log.info("预热ZjfModuleLocalServiceImpl缓存");
        // 1.先查询出用户
        List<String> users = this.distinctUser();
        for (String user : users) {
            // 2.再预热每个用户的数据
            this.queryAllByUser(user);
        }
    }

    private List<String> distinctUser() {
        ZjfModuleLocalEntity entity = new ZjfModuleLocalEntity();
        QueryWrapper<ZjfModuleLocalEntity> wrapper = new QueryWrapper<>(entity)
                .select("DISTINCT `user`");
        List<ZjfModuleLocalEntity> moduleLocalEntities = zjfModuleLocalMapper.selectList(wrapper);
        return moduleLocalEntities
                .stream()
                .map(ZjfModuleLocalEntity::getUser)
                .collect(Collectors.toList());
    }
}